package com.study.hotreloadsample.hotReload;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 作者： zjf 10/10/20 4:43 PM
 * 参考：
 * 描述：
 */
public class ReflectUtil {

    /**
     * 在obj或其父类中寻找属性
     *
     * @param obj  类
     * @param name 属性名
     * @return 属性实体
     */
    public static Field findField(Object obj, String name) throws NoSuchFieldException {
        //执行此方法,第一步从当前clazz中去寻找,找到就返回,找不到去其父类中寻找
        for (Class<?> clazz = obj.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
            //需要执行try catch(当前类没有找到,捕获异常,继续在父类中找)
            try {
                //找到需要的成员变量
                Field field = clazz.getDeclaredField(name);

                //打开访问权限
                if (!field.isAccessible()) {
                    field.setAccessible(true);
                }
                return field;

            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }

        throw new NoSuchFieldException("Field:" + name + "not found");
    }

    /**
     * 在当前类或其父类中寻找指定的方法
     *
     * @param obj            当前类
     * @param name           方法名
     * @param parameterTypes 方法参数类型
     * @return 方法实体
     */
    public static Method findMethod(Object obj, String name, Class<?>... parameterTypes) throws NoSuchMethodException {
        for (Class<?> clazz = obj.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
            try {
                Method method = clazz.getDeclaredMethod(name, parameterTypes);
                if (!method.isAccessible()) {
                    method.setAccessible(true);
                }
                return method;
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
        throw new NoSuchMethodException("Method:" + name + "not found");
    }

    /**
     * 把已修复的dex数组,添加到pathList
     *
     * @param obj           类加载器
     * @param fieldName     成员变量属性名称
     * @param patchElements 修复的dex文件数组
     */
    public static void expendFieldArray(Object obj, String fieldName, Object[] patchElements) throws NoSuchFieldException, IllegalAccessException {

        //拿到类加载器中的保存dexElement的pathList数组的Field
        Field dexElementsField = findField(obj, fieldName);
        //获取内容
        Object[] dexElements = (Object[]) dexElementsField.get(obj);

        //建立一个新的数组用于存放所有的dexElement
        Object[] newElements = (Object[]) Array.newInstance(dexElements.getClass().getComponentType(), dexElements.length + patchElements.length);

        //把所有的dexElements拷贝到新数组,修复后的数组在前面
        System.arraycopy(patchElements, 0, newElements, 0, patchElements.length);
        System.arraycopy(dexElements, 0, newElements, patchElements.length, dexElements.length);

        dexElementsField.set(obj, newElements);
    }
}
